// ============================================================================
//
// LCP-net framework by Pierre CHATEL chatelp@gmail.com
// Distributed under GPLv3
// Copyright (C) THALES Land & Joint Systems, 2008, 2009. All rights reserved
//
// ============================================================================

/**
 * <copyright>
 * </copyright>
 *
 * $Id$
 */
package com.thalesgroup.preferenceFramework.models.LCPnet.fragments.impl;

import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;

import com.thalesgroup.preferenceFramework.models.Arc;
import com.thalesgroup.preferenceFramework.models.NodeValue;
import com.thalesgroup.preferenceFramework.models.LCPnet.CLPT;
import com.thalesgroup.preferenceFramework.models.LCPnet.LCPnet;
import com.thalesgroup.preferenceFramework.models.LCPnet.LNode;
import com.thalesgroup.preferenceFramework.models.LCPnet.LNodeValue;
import com.thalesgroup.preferenceFramework.models.LCPnet.LinguisticDomain;
import com.thalesgroup.preferenceFramework.models.LCPnet.exceptions.LCPnetCombinationException;
import com.thalesgroup.preferenceFramework.models.LCPnet.fragments.CITLineFragment;
import com.thalesgroup.preferenceFramework.models.LCPnet.fragments.CLPTFragment;
import com.thalesgroup.preferenceFramework.models.LCPnet.fragments.Fragment;
import com.thalesgroup.preferenceFramework.models.LCPnet.fragments.FragmentsPackage;
import com.thalesgroup.preferenceFramework.models.LCPnet.fragments.LCPnetFragment;
import com.thalesgroup.preferenceFramework.models.LCPnet.fragments.LNodeFragment;
import com.thalesgroup.preferenceFramework.models.LCPnet.fragments.LNodeValueFragment;
import com.thalesgroup.preferenceFramework.models.LCPnet.fragments.LinguisticDomainFragment;
import com.thalesgroup.preferenceFramework.models.LCPnet.impl.LNodeImpl;

/**
 * <!-- begin-user-doc -->
 * An implementation of the model object '<em><b>LNode Fragment</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * <ul>
 *   <li>{@link com.thalesgroup.preferenceFramework.models.LCPnet.fragments.impl.LNodeFragmentImpl#getFragmentName <em>Fragment Name</em>}</li>
 *   <li>{@link com.thalesgroup.preferenceFramework.models.LCPnet.fragments.impl.LNodeFragmentImpl#isAntiFragment <em>Anti Fragment</em>}</li>
 *   <li>{@link com.thalesgroup.preferenceFramework.models.LCPnet.fragments.impl.LNodeFragmentImpl#getBaseLNode <em>Base LNode</em>}</li>
 * </ul>
 * </p>
 *
 * @generated
 */
public class LNodeFragmentImpl extends LNodeImpl implements LNodeFragment {
	/**
	 * The default value of the '{@link #getFragmentName() <em>Fragment Name</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getFragmentName()
	 * @generated
	 * @ordered
	 */
	protected static final String FRAGMENT_NAME_EDEFAULT = "";
	/**
	 * The cached value of the '{@link #getFragmentName() <em>Fragment Name</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getFragmentName()
	 * @generated
	 * @ordered
	 */
	protected String fragmentName = FRAGMENT_NAME_EDEFAULT;
	/**
	 * The default value of the '{@link #isAntiFragment() <em>Anti Fragment</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #isAntiFragment()
	 * @generated
	 * @ordered
	 */
	protected static final boolean ANTI_FRAGMENT_EDEFAULT = false;
	/**
	 * The cached value of the '{@link #isAntiFragment() <em>Anti Fragment</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #isAntiFragment()
	 * @generated
	 * @ordered
	 */
	protected boolean antiFragment = ANTI_FRAGMENT_EDEFAULT;
	/**
	 * The cached value of the '{@link #getBaseLNode() <em>Base LNode</em>}' reference.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getBaseLNode()
	 * @generated
	 * @ordered
	 */
	protected LNode baseLNode;

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	protected LNodeFragmentImpl() {
		super();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	protected EClass eStaticClass() {
		return FragmentsPackage.Literals.LNODE_FRAGMENT;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public String getFragmentName() {
		return fragmentName;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setFragmentName(String newFragmentName) {
		String oldFragmentName = fragmentName;
		fragmentName = newFragmentName;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, FragmentsPackage.LNODE_FRAGMENT__FRAGMENT_NAME, oldFragmentName, fragmentName));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public boolean isAntiFragment() {
		return antiFragment;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setAntiFragment(boolean newAntiFragment) {
		boolean oldAntiFragment = antiFragment;
		antiFragment = newAntiFragment;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, FragmentsPackage.LNODE_FRAGMENT__ANTI_FRAGMENT, oldAntiFragment, antiFragment));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public LNode getBaseLNode() {
		if (baseLNode != null && baseLNode.eIsProxy()) {
			InternalEObject oldBaseLNode = (InternalEObject)baseLNode;
			baseLNode = (LNode)eResolveProxy(oldBaseLNode);
			if (baseLNode != oldBaseLNode) {
				if (eNotificationRequired())
					eNotify(new ENotificationImpl(this, Notification.RESOLVE, FragmentsPackage.LNODE_FRAGMENT__BASE_LNODE, oldBaseLNode, baseLNode));
			}
		}
		return baseLNode;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public LNode basicGetBaseLNode() {
		return baseLNode;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setBaseLNode(LNode newBaseLNode) {
		LNode oldBaseLNode = baseLNode;
		baseLNode = newBaseLNode;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, FragmentsPackage.LNODE_FRAGMENT__BASE_LNODE, oldBaseLNode, baseLNode));
	}

	public void applyFragment(EObject context) throws LCPnetCombinationException {
		if(context instanceof LCPnetFragment) {
			//Fragment contained in context --> apply fragment

			LNode baseLNode = this.getBaseLNode();

			if(this.isAntiFragment()) {
				LCPnet baseLCPnet = (LCPnet) baseLNode.getPreferenceNetwork();
				baseLCPnet.getNodes().remove(baseLNode);
				return;
			}

			//Warning: If it's an antiFragment, the following code will not be executed

			if(this.getName() != null && !this.getName().equals("")) {
				baseLNode.setName(this.getName());
			}

			if(this.getInArcs() != null) {
				EList<Arc> inArcs = this.getInArcs();
				//Avoid list concurrent modifications
				Arc[] inArcs_array = inArcs.toArray(new Arc[]{});
				
				for (Arc arc : inArcs_array) {
					if(arc instanceof Fragment) {
						//If arc, iarc, ciarc fragment --> apply fragment
						((Fragment) arc).applyFragment(this);
					}
					else {
						//If new arc, iarc, ciarc --> add to base LNode relations (and set opposite relation)
						arc.setEndNode(baseLNode);
					}
				}
			}

			if(this.getOutArcs() != null) {
				EList<Arc> outArcs = this.getOutArcs();
				//Avoid list concurrent modifications
				Arc[] outArcs_array = outArcs.toArray(new Arc[]{});
				
				for (Arc arc : outArcs_array) {
					if(arc instanceof Fragment) {
						//If arc, iarc, ciarc fragment --> apply fragment
						((Fragment) arc).applyFragment(this);
					}
					else {
						//If new arc, iarc, ciarc --> add to base LNode relations (and set opposite relation)
						arc.setStartNode(baseLNode);
					}
				}
			}

			if(this.getDomain() != null) {
				EList<NodeValue> domain = this.getDomain();
				//Avoid list concurrent modifications
				NodeValue[] domain_array = domain.toArray(new NodeValue[]{});
				
				for (NodeValue nodeValue : domain_array) {
					if(nodeValue instanceof LNodeValueFragment) {
						((LNodeValueFragment) nodeValue).applyFragment(this);
					} else if(nodeValue instanceof LNodeValue) {
						LNodeValue lnodeValue = (LNodeValue) nodeValue;				
						//add node value to base lnode
						lnodeValue.setNode(baseLNode);
					} else {
						throw new LCPnetCombinationException(
								"Fragment consistancy error: bad type for " + nodeValue);
					}
				}
			}

			if(this.getValueDomain() != null) {
				LinguisticDomain valueDomain = this.getValueDomain();
				
				if(valueDomain instanceof LinguisticDomainFragment) {
					//If LinguisticDomain fragment --> apply fragment
					((LinguisticDomainFragment) valueDomain).applyFragment(this);
				} else {
					//it's not a fragment, we overwrite the old value
					baseLNode.setValueDomain(valueDomain);
				}
			}

			if(this.getLinguisticTable() != null) {
				CLPT linguisticTable = this.getLinguisticTable();
				
				if(linguisticTable instanceof CLPTFragment) {
					//If CLPT fragment --> apply fragment
					((CLPTFragment) linguisticTable).applyFragment(this);
				} else {
					//If new CLPT --> overwrite base CLPT value
					baseLNode.setLinguisticTable(linguisticTable);
				}
			}
			
		} else if(context instanceof CITLineFragment) {
			throw new LCPnetCombinationException("Usage error: cannot link an CITLineFragment to an LNodeFragment, only LNode");
			
		} else {
			throw new LCPnetCombinationException("Combination error: unexpected calling context for node fragment");
		
		}
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eGet(int featureID, boolean resolve, boolean coreType) {
		switch (featureID) {
			case FragmentsPackage.LNODE_FRAGMENT__FRAGMENT_NAME:
				return getFragmentName();
			case FragmentsPackage.LNODE_FRAGMENT__ANTI_FRAGMENT:
				return isAntiFragment() ? Boolean.TRUE : Boolean.FALSE;
			case FragmentsPackage.LNODE_FRAGMENT__BASE_LNODE:
				if (resolve) return getBaseLNode();
				return basicGetBaseLNode();
		}
		return super.eGet(featureID, resolve, coreType);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eSet(int featureID, Object newValue) {
		switch (featureID) {
			case FragmentsPackage.LNODE_FRAGMENT__FRAGMENT_NAME:
				setFragmentName((String)newValue);
				return;
			case FragmentsPackage.LNODE_FRAGMENT__ANTI_FRAGMENT:
				setAntiFragment(((Boolean)newValue).booleanValue());
				return;
			case FragmentsPackage.LNODE_FRAGMENT__BASE_LNODE:
				setBaseLNode((LNode)newValue);
				return;
		}
		super.eSet(featureID, newValue);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eUnset(int featureID) {
		switch (featureID) {
			case FragmentsPackage.LNODE_FRAGMENT__FRAGMENT_NAME:
				setFragmentName(FRAGMENT_NAME_EDEFAULT);
				return;
			case FragmentsPackage.LNODE_FRAGMENT__ANTI_FRAGMENT:
				setAntiFragment(ANTI_FRAGMENT_EDEFAULT);
				return;
			case FragmentsPackage.LNODE_FRAGMENT__BASE_LNODE:
				setBaseLNode((LNode)null);
				return;
		}
		super.eUnset(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public boolean eIsSet(int featureID) {
		switch (featureID) {
			case FragmentsPackage.LNODE_FRAGMENT__FRAGMENT_NAME:
				return FRAGMENT_NAME_EDEFAULT == null ? fragmentName != null : !FRAGMENT_NAME_EDEFAULT.equals(fragmentName);
			case FragmentsPackage.LNODE_FRAGMENT__ANTI_FRAGMENT:
				return antiFragment != ANTI_FRAGMENT_EDEFAULT;
			case FragmentsPackage.LNODE_FRAGMENT__BASE_LNODE:
				return baseLNode != null;
		}
		return super.eIsSet(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public int eBaseStructuralFeatureID(int derivedFeatureID, Class<?> baseClass) {
		if (baseClass == Fragment.class) {
			switch (derivedFeatureID) {
				case FragmentsPackage.LNODE_FRAGMENT__FRAGMENT_NAME: return FragmentsPackage.FRAGMENT__FRAGMENT_NAME;
				case FragmentsPackage.LNODE_FRAGMENT__ANTI_FRAGMENT: return FragmentsPackage.FRAGMENT__ANTI_FRAGMENT;
				default: return -1;
			}
		}
		return super.eBaseStructuralFeatureID(derivedFeatureID, baseClass);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public int eDerivedStructuralFeatureID(int baseFeatureID, Class<?> baseClass) {
		if (baseClass == Fragment.class) {
			switch (baseFeatureID) {
				case FragmentsPackage.FRAGMENT__FRAGMENT_NAME: return FragmentsPackage.LNODE_FRAGMENT__FRAGMENT_NAME;
				case FragmentsPackage.FRAGMENT__ANTI_FRAGMENT: return FragmentsPackage.LNODE_FRAGMENT__ANTI_FRAGMENT;
				default: return -1;
			}
		}
		return super.eDerivedStructuralFeatureID(baseFeatureID, baseClass);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public String toString() {
		if (eIsProxy()) return super.toString();

		StringBuffer result = new StringBuffer(super.toString());
		result.append(" (fragmentName: ");
		result.append(fragmentName);
		result.append(", antiFragment: ");
		result.append(antiFragment);
		result.append(')');
		return result.toString();
	}

} //LNodeFragmentImpl
